//
//  UIGestureRecognizer+ALExtension.swift
//  ALCore
//
//  Created by IdeaBank on 2023/12/18.
//

import Foundation


public extension ALGestureRecognizerExtensions where Base: UIGestureRecognizer {

    /// 并添加手势闭包事件
    static func gestureClosure(_ handler: @escaping (_ sender: Base) -> Void) -> Base {
        let owner = Base()
        owner.an_addGesture(handler: { handler($0 as! Base) })
        return owner
    }

    /// 为手势识别器并添加闭包事件
    func gestureClosure(_ handler: @escaping (_ sender: Base) -> Void) {
        base.an_addGesture(handler: { handler($0 as! Base) })
    }

    /// 移除所有手势识别器闭包事件
    func clearGestureClosures() {
        base.an_removeGestureHandlers()
    }
}

private var UIGestureRecognizerAssociatedWrappersKey: Void?

private extension UIGestureRecognizer {

    var an_wrappers: [_ANGestureRecognizerWrapper<UIGestureRecognizer>]? {
        get {
            return objc_getAssociatedObject(self, &UIGestureRecognizerAssociatedWrappersKey) as? [_ANGestureRecognizerWrapper]
        } set {
            objc_setAssociatedObject(self, &UIGestureRecognizerAssociatedWrappersKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    func an_addGesture(handler: @escaping (_ sender: UIGestureRecognizer) -> Void) {
        if an_wrappers == nil { an_wrappers = Array() }
        let target = _ANGestureRecognizerWrapper(handler: handler)
        an_wrappers?.append(target)
        self.addTarget(target, action: target.method)
    }

    func an_removeGestureHandlers() {
        if var events = an_wrappers, !events.isEmpty {
            for target in events {
                self.removeTarget(target, action: target.method)
            }
            events.removeAll()
            an_wrappers = nil
        }
    }

}

private class _ANGestureRecognizerWrapper<T> {
    var block: ((_ sender: T) -> Void)?
    let method = #selector(invoke(_:))

    init(handler: @escaping (_ sender: T) -> Void) {
        block = handler
    }

    @objc func invoke(_ sender: UIGestureRecognizer)  {
        block?(sender as! T)
    }
}

public struct ALGestureRecognizerExtensions<Base> {
    fileprivate var base: Base
    fileprivate init(_ base: Base) { self.base = base }
}

public protocol ALGestureRecognizerExtensionsCompatible {}

public extension ALGestureRecognizerExtensionsCompatible {
    static var action: ALGestureRecognizerExtensions<Self>.Type { ALGestureRecognizerExtensions<Self>.self }
    var action: ALGestureRecognizerExtensions<Self> { get{ ALGestureRecognizerExtensions(self) } set{} }
}

extension UIGestureRecognizer: ALGestureRecognizerExtensionsCompatible {}


//MARK: - 链式属性函数
extension UIGestureRecognizer {

    /// 代理
    /// - Parameter delegate: 代理
    /// - Returns: 自身
    @discardableResult
    public func delegate(_ delegate: UIGestureRecognizerDelegate?) -> Self {
        self.delegate = delegate
        return self
    }

    /// 手势是否有效
    /// - Parameter enable: 是否有效
    /// - Returns: 自身
    @discardableResult
    public func isEnabled(_ enable: Bool) -> Self {
        self.isEnabled = enable
        return self
    }

    /// 是否取消手势在其视图事件链上的传递 默认 true
    /// - Parameter isCancel: 是否取消
    /// - Returns: 自身
    @discardableResult
    public func cancelsTouchesInView(_ isCancel: Bool = true) -> Self {
        cancelsTouchesInView = isCancel
        return self
    }

    ///手势识别之前是否推迟事件传递 默认 false
    /// - Parameter isDelays: 是否延迟
    /// - Returns: 自身
    @discardableResult
    public func delaysTouchesBegan(_ isDelays: Bool = false) -> Self {
        delaysTouchesBegan = isDelays
        return self
    }

    /// 手势识别结束之后是否推迟事件传递 默认 false
    /// - Parameter isDelays: 是否延迟
    /// - Returns: 自身
    @discardableResult
    public func delaysTouchesEnded(_ isDelays: Bool = false) -> Self {
        delaysTouchesEnded = isDelays
        return self
    }

    /// 该手势需其他手势识别失败之后执行 即优先执行其他手势事件
    /// - Parameter otherGesture: 其他手势
    /// - Returns: 自身
    @discardableResult
    public func require(after otherGesture: UIGestureRecognizer) -> Self {
        require(toFail: otherGesture)
        return self
    }

    /// 添加手势
    /// - Parameter view: 视图
    /// - Returns: 自身
    @discardableResult
    public func addGestureTo(_ view: UIView) -> Self {
        view.addGestureRecognizer(self)
        return self
    }

    /// 移除手势
    /// - Parameter view: 视图
    /// - Returns: 自身
    @discardableResult
    public func removeGestureTo(_ view: UIView) -> Self {
        view.removeGestureRecognizer(self)
        return self
    }
}

extension UITapGestureRecognizer {

    /// 要求的点击数 默认 1
    /// - Parameter nums: 点击数
    /// - Returns: 自身
    @discardableResult
    public func numberOfTapsRequired(_ nums: Int = 1) -> Self {
        numberOfTapsRequired = nums
        return self
    }

    /// 要求的触摸点数 默认 1
    /// - Parameter nums: 触摸点数
    /// - Returns: 自身
    @discardableResult
    public func numberOfTouchesRequired(_ nums: Int = 1) -> Self {
        numberOfTouchesRequired = nums
        return self
    }
}

extension UILongPressGestureRecognizer {

    /// 长按之前要求的点击数 默认 0
    /// - Parameter nums: 点击数
    /// - Returns: 自身
    @discardableResult
    public func numberOfTapsRequired(_ nums: Int = 0) -> Self {
        numberOfTapsRequired = nums
        return self
    }

    /// 要求的触摸点数 默认 1
    /// - Parameter nums: 触摸点数
    /// - Returns: 自身
    @discardableResult
    public func numberOfTouchesRequired(_ nums: Int = 1) -> Self {
        numberOfTouchesRequired = nums
        return self
    }

    /// 长按要求的最低时长 默认 0.5s
    /// - Parameter duration: 长按时长
    /// - Returns: 自身
    @discardableResult
    public func minimumPressDuration(_ duration: TimeInterval = 0.5) -> Self {
        minimumPressDuration = duration
        return self
    }

    /// 手势识别之前允许的最大移动距离 默认 10 px
    /// - Parameter distance: 最大距离 单位 px
    /// - Returns: 自身
    @discardableResult
    public func allowableMovement(_ distance: CGFloat = 10) -> Self {
        allowableMovement = distance
        return self
    }
}

extension UIPanGestureRecognizer {

    /// 要求的最低触摸点数 默认 1
    /// - Parameter nums: 触摸点数
    /// - Returns: 自身
    @discardableResult
    public func minimumNumberOfTouches(_ nums: Int = 1) -> Self {
        minimumNumberOfTouches = nums
        return self
    }

    /// 要求的最大触摸点数 默认无穷大 ∞
    /// - Parameter nums: 触摸点数
    /// - Returns: 自身
    @discardableResult
    public func maximumNumberOfTouches(_ nums: Int = Int(UInt.max)) -> Self {
        maximumNumberOfTouches = nums
        return self
    }
}

extension UISwipeGestureRecognizer {

    /// 要求的触摸点数 默认 1
    /// - Parameter nums: 触摸点数
    /// - Returns: 自身
    @discardableResult
    public func numberOfTouchesRequired(_ nums: Int = 1) -> Self {
        numberOfTouchesRequired = nums
        return self
    }

    /// 清扫方向 默认向右清扫
    /// 若是多个方向执行同样的操作则可指定多个方向 否则应一个方向指定发一个清扫手势
    /// - Parameter direction: 清扫方向
    /// - Returns: 自身
    @discardableResult
    public func direction(_ direction: UISwipeGestureRecognizer.Direction = .right) -> Self {
        self.direction = direction
        return self
    }
}

extension UIPinchGestureRecognizer {

    /// 捏合手势的比例
    /// - Parameter scale: 捏合比例
    /// - Returns: 自身
    @discardableResult
    public func scale(_ scale: CGFloat) -> Self {
        self.scale = scale
        return self
    }
}

extension UIRotationGestureRecognizer {

    /// 旋转手势的比例 其中以开始为基点 顺时针旋转 rotation 减小 逆时针旋转 rotation 增大
    /// - Parameter rotation: 旋转比例
    /// - Returns: 自身
    @discardableResult
    public func rotation(_ rotation: CGFloat) -> Self {
        self.rotation = rotation
        return self
    }
}

extension UIScreenEdgePanGestureRecognizer {

    /// 旋转手势的比例 其中以开始为基点 顺时针旋转 rotation 减小 逆时针旋转 rotation 增大
    /// - Parameter rotation: 旋转比例
    /// - Returns: 自身
    @discardableResult
    public func edges(_ edges: UIRectEdge) -> Self {
        self.edges = edges
        return self
    }
}

//MARK: - 手势事件
extension UIGestureRecognizer {

    /// 添加手势事件
    public func addGesture(_ action: @escaping (UIGestureRecognizer) -> Void) {
        addTarget(self, action: #selector(self.clickGesture))
        objc_setAssociatedObject(
            self,
            &AssociatedKey.associatedGestureEvent,
            action,
            .OBJC_ASSOCIATION_COPY_NONATOMIC
        )
    }
}

fileprivate extension UIGestureRecognizer {

    @objc func clickGesture() {
        if let event = objc_getAssociatedObject(
            self,
            &AssociatedKey.associatedGestureEvent
        ) as? ((UIGestureRecognizer) -> (Void)) {
            event(self)
        }
    }

    struct AssociatedKey {
        static var associatedGestureEvent: Void?
    }
}
